package pers.jason.wppm.security.core.validate.code.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;

import pers.jason.wppm.security.core.properties.SecurityProperties;
import pers.jason.wppm.security.core.validate.code.exception.ValidateCodeException;
import pers.jason.wppm.security.core.validate.code.processor.impl.AbstractValidateCodeTemplate;
import pers.jason.wppm.security.core.validate.code.support.ValidateCodeType;

/**
 * 校验验证码是否正确
 * @author Jason
 * @Date 2018-10-30 16:46
 *
 */
@Component("validateCodeFilter")
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
	
	@Autowired
	private Map<String, AbstractValidateCodeTemplate<?>> processors;
	
	private AntPathMatcher pathMatcher = new AntPathMatcher();
	
	/**
	 * key : url
	 * value : code type
	 */
	private Map<String, ValidateCodeType> needValidateUrl = new HashMap<>();
	
	@Autowired
	private SecurityProperties securityProperties;
	
	/**
	 * 获取系统已经装配的认证失败处理器
	 */
	@Autowired
	private AuthenticationFailureHandler authenticationFailureHandler;
	
	@Override
	public void afterPropertiesSet() throws ServletException {
		// TODO Auto-generated method stub
		//登录请求需要校验验证码
		String formLoginUrl = securityProperties.getBrowser().getFormLoginUrl();
		String mobileLoginUrl = securityProperties.getBrowser().getMobileLoginUrl();
		String smsCodeValidateUrls = securityProperties.getCode().getSms().getValidateUrls();
		String imageCodeValidateUrls = securityProperties.getCode().getImage().getValidateUrls();
		needValidateUrl.put(formLoginUrl, ValidateCodeType.IMAGE);
		needValidateUrl.put(mobileLoginUrl, ValidateCodeType.SMS);
		if(!StringUtils.isEmpty(smsCodeValidateUrls)) {
			for(String url : StringUtils.split(smsCodeValidateUrls, ",")) {
				needValidateUrl.put(url, ValidateCodeType.SMS);
			}
		}
		if(!StringUtils.isEmpty(imageCodeValidateUrls)) {
			for(String url : StringUtils.split(imageCodeValidateUrls, ",")) {
				needValidateUrl.put(url, ValidateCodeType.IMAGE);
			}
		}
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		String beanName = getProcessorBeanName(request);
		if(!StringUtils.isEmpty(beanName)) {
			try {
				AbstractValidateCodeTemplate<?> processor = processors.get(beanName);
				processor.validateCode(new ServletWebRequest(request, response));
			} catch(ValidateCodeException e) {
				logger.info(e.getMessage());
				authenticationFailureHandler.onAuthenticationFailure(request, response, e);
				return;
			}
		}
		filterChain.doFilter(request, response);
	}
	
	private String getProcessorBeanName(HttpServletRequest request) {
		String result = "";
		String requestUri = request.getRequestURI();
		for(String key : needValidateUrl.keySet()) {
			if(pathMatcher.match(key, requestUri)) {
				result =  needValidateUrl.get(key).getTypeName();
				break;
			}
		}		
		return StringUtils.isEmpty(result) ? "" : result+"ValidateCodeProcessor";
	}


}
